//! Storage layer implementation
//! 
//! This module provides data persistence capabilities for the platform.

pub mod database;
pub mod database_config;
pub mod file_system;
pub mod cache;

// Re-export key types
pub use database::DatabaseStorage;
pub use database_config::{DatabaseConfig, CacheConfig, StorageConfig, StorageManager as DatabaseStorageManager, StorageHealth};
pub use file_system::FileSystemStorage;
pub use cache::{MemoryCache, RedisCache};

use crate::error::Result;
use crate::models::{
    testcase::TestCase,
    step::StepResult,
    summary::{TestSummary, TestCaseSummary},
    Value, ValueMap,
};
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use uuid::Uuid;

/// Storage trait for test data persistence
#[async_trait]
pub trait TestStorage: Send + Sync {
    /// Save a test case
    async fn save_test_case(&self, test_case: &TestCase) -> Result<()>;
    
    /// Load a test case by ID
    async fn load_test_case(&self, id: Uuid) -> Result<TestCase>;
    
    /// Save a test result
    async fn save_test_result(&self, result: &StepResult) -> Result<()>;
    
    /// Load test results by test case ID
    async fn load_test_results(&self, test_case_id: Uuid) -> Result<Vec<StepResult>>;
    
    /// Save a test summary
    async fn save_test_summary(&self, summary: &TestSummary) -> Result<()>;
    
    /// Load a test summary by ID
    async fn load_test_summary(&self, id: Uuid) -> Result<TestSummary>;
    
    /// Query test results with filters
    async fn query_test_results(&self, query: &TestResultQuery) -> Result<Vec<StepResult>>;
    
    /// Get test metrics for a time range
    async fn get_test_metrics(&self, query: &MetricsQuery) -> Result<ValueMap>;
    
    /// Delete old test data
    async fn cleanup_old_data(&self, before: DateTime<Utc>) -> Result<usize>;
}

/// Cache trait for temporary data storage
#[async_trait]
pub trait TestCache: Send + Sync {
    /// Set a value in cache
    async fn set(&self, key: &str, value: &Value, ttl: Option<u64>) -> Result<()>;
    
    /// Get a value from cache
    async fn get(&self, key: &str) -> Result<Option<Value>>;
    
    /// Delete a value from cache
    async fn delete(&self, key: &str) -> Result<bool>;
    
    /// Check if key exists
    async fn exists(&self, key: &str) -> Result<bool>;
    
    /// Set expiration for a key
    async fn expire(&self, key: &str, ttl: u64) -> Result<bool>;
    
    /// Clear all cache
    async fn clear(&self) -> Result<()>;
}

/// Test result query parameters
#[derive(Debug, Clone)]
pub struct TestResultQuery {
    /// Test case IDs to filter by
    pub test_case_ids: Option<Vec<Uuid>>,
    
    /// Start time filter
    pub start_time: Option<DateTime<Utc>>,
    
    /// End time filter
    pub end_time: Option<DateTime<Utc>>,
    
    /// Success status filter
    pub success: Option<bool>,
    
    /// Step type filter
    pub step_types: Option<Vec<String>>,
    
    /// Limit number of results
    pub limit: Option<usize>,
    
    /// Offset for pagination
    pub offset: Option<usize>,
    
    /// Sort order
    pub sort_by: Option<String>,
    
    /// Sort direction
    pub sort_desc: bool,
}

/// Metrics query parameters
#[derive(Debug, Clone)]
pub struct MetricsQuery {
    /// Start time
    pub start_time: DateTime<Utc>,
    
    /// End time
    pub end_time: DateTime<Utc>,
    
    /// Metric types to include
    pub metrics: Vec<String>,
    
    /// Group by field
    pub group_by: Option<String>,
    
    /// Aggregation function
    pub aggregation: Option<String>,
}

impl TestResultQuery {
    /// Create a new query
    pub fn new() -> Self {
        Self {
            test_case_ids: None,
            start_time: None,
            end_time: None,
            success: None,
            step_types: None,
            limit: None,
            offset: None,
            sort_by: None,
            sort_desc: false,
        }
    }
    
    /// Filter by test case IDs
    pub fn with_test_case_ids(mut self, ids: Vec<Uuid>) -> Self {
        self.test_case_ids = Some(ids);
        self
    }
    
    /// Filter by time range
    pub fn with_time_range(mut self, start: DateTime<Utc>, end: DateTime<Utc>) -> Self {
        self.start_time = Some(start);
        self.end_time = Some(end);
        self
    }
    
    /// Filter by success status
    pub fn with_success(mut self, success: bool) -> Self {
        self.success = Some(success);
        self
    }
    
    /// Limit results
    pub fn with_limit(mut self, limit: usize) -> Self {
        self.limit = Some(limit);
        self
    }
    
    /// Set offset for pagination
    pub fn with_offset(mut self, offset: usize) -> Self {
        self.offset = Some(offset);
        self
    }
    
    /// Sort by field
    pub fn sort_by(mut self, field: String, desc: bool) -> Self {
        self.sort_by = Some(field);
        self.sort_desc = desc;
        self
    }
}

impl MetricsQuery {
    /// Create a new metrics query
    pub fn new(start_time: DateTime<Utc>, end_time: DateTime<Utc>) -> Self {
        Self {
            start_time,
            end_time,
            metrics: vec![
                "total_tests".to_string(),
                "success_rate".to_string(),
                "avg_duration".to_string(),
            ],
            group_by: None,
            aggregation: None,
        }
    }
    
    /// Set metrics to include
    pub fn with_metrics(mut self, metrics: Vec<String>) -> Self {
        self.metrics = metrics;
        self
    }
    
    /// Group by field
    pub fn group_by(mut self, field: String) -> Self {
        self.group_by = Some(field);
        self
    }
    
    /// Set aggregation function
    pub fn with_aggregation(mut self, aggregation: String) -> Self {
        self.aggregation = Some(aggregation);
        self
    }
}

impl Default for TestResultQuery {
    fn default() -> Self {
        Self::new()
    }
}

/// Storage manager that combines different storage backends
pub struct StorageManager {
    /// Primary storage backend
    storage: Box<dyn TestStorage>,

    /// Cache backend
    cache: Option<Box<dyn TestCache>>,
}

impl StorageManager {
    /// Create a new storage manager
    pub fn new(storage: Box<dyn TestStorage>) -> Self {
        Self {
            storage,
            cache: None,
        }
    }
    
    /// Add cache backend
    pub fn with_cache(mut self, cache: Box<dyn TestCache>) -> Self {
        self.cache = Some(cache);
        self
    }
    
    /// Get storage backend
    pub fn storage(&self) -> &dyn TestStorage {
        self.storage.as_ref()
    }
    
    /// Get cache backend
    pub fn cache(&self) -> Option<&dyn TestCache> {
        self.cache.as_ref().map(|c| c.as_ref())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_test_result_query_builder() {
        let query = TestResultQuery::new()
            .with_success(true)
            .with_limit(100)
            .sort_by("start_time".to_string(), true);
        
        assert_eq!(query.success, Some(true));
        assert_eq!(query.limit, Some(100));
        assert_eq!(query.sort_by, Some("start_time".to_string()));
        assert!(query.sort_desc);
    }

    #[test]
    fn test_metrics_query_builder() {
        let start = Utc::now();
        let end = start + chrono::Duration::hours(1);
        
        let query = MetricsQuery::new(start, end)
            .with_metrics(vec!["success_rate".to_string()])
            .group_by("test_type".to_string());
        
        assert_eq!(query.metrics, vec!["success_rate".to_string()]);
        assert_eq!(query.group_by, Some("test_type".to_string()));
    }
}
